//     Zepto.js
//     (c) 2010-2016 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

(function ($) {
  // Create a collection of callbacks to be fired in a sequence, with configurable behaviour
  // Option flags:
  //   - once: Callbacks fired at most one time.
  //   - memory: Remember the most recent context and arguments
  //   - stopOnFalse: Cease iterating over callback list
  //   - unique: Permit adding at most one instance of the same callback
  										$.Callbacks = function (options) {
    										options = $.extend({}, options);

    										var memory, // Last fire value (for non-forgettable lists)
        										fired,  // Flag to know if list was already fired
        										firing, // Flag to know if list is currently firing
        										firingStart, // First callback to fire (used internally by add and fireWith)
        										firingLength, // End of the loop when firing
        										firingIndex, // Index of currently firing callback (modified by remove if needed)
        										list = [], // Actual callback list
        										stack = !options.once && [], // Stack of fire calls for repeatable lists
        										fire = function (data) {
          										memory = options.memory && data;
          										fired = true;
          										firingIndex = firingStart || 0;
          										firingStart = 0;
          										firingLength = list.length;
          										firing = true;
          										for (; list && firingIndex < firingLength; ++firingIndex) {
            										if (list[firingIndex].apply(data[0], data[1]) === false && options.stopOnFalse) {
              										memory = false;
              										break;
            }
          }
          										firing = false;
          										if (list) {
            										if (stack) stack.length && fire(stack.shift());
            										else if (memory) list.length = 0;
            else Callbacks.disable();
          }
        },

        										Callbacks = {
          										add() {
            										if (list) {
              										var start = list.length,
                  										add = function (args) {
                    										$.each(args, function (_, arg) {
                      										if (typeof arg === 'function') {
                        										if (!options.unique || !Callbacks.has(arg)) list.push(arg);
                      }
                      										else if (arg && arg.length && typeof arg !== 'string') add(arg);
                    });
                  };
              										add(arguments);
              										if (firing) firingLength = list.length;
              										else if (memory) {
                										firingStart = start;
                										fire(memory);
              }
            }
            										return this;
          },
          										remove() {
            										if (list) {
              										$.each(arguments, function (_, arg) {
                										var index;
                										while ((index = $.inArray(arg, list, index)) > -1) {
                  										list.splice(index, 1);
                  // Handle firing indexes
                  										if (firing) {
                    										if (index <= firingLength) --firingLength;
                    										if (index <= firingIndex) --firingIndex;
                  }
                }
              });
            }
            										return this;
          },
          										has(fn) {
            										return !!(list && (fn ? $.inArray(fn, list) > -1 : list.length));
          },
          										empty() {
            										firingLength = list.length = 0;
            										return this;
          },
          										disable() {
            										list = stack = memory = undefined;
            										return this;
          },
          										disabled() {
            										return !list;
          },
          										lock() {
            										stack = undefined;
            										if (!memory) Callbacks.disable();
            										return this;
          },
          										locked() {
            										return !stack;
          },
          										fireWith(context, args) {
            										if (list && (!fired || stack)) {
              										args = args || [];
              										args = [context, args.slice ? args.slice() : args];
              										if (firing) stack.push(args);
              										else fire(args);
            }
            										return this;
          },
          										fire() {
            										return Callbacks.fireWith(this, arguments);
          },
          										fired() {
            										return !!fired;
          }
        };

    										return Callbacks;
  };
})(Zepto);
